#include "uart_test.h"
#include "at32f435_437.h"
#include "board.h"
#include "config_api.h"
#include "factory_api.h"
#include "module_queue_struct.h"
#include "serial_app.h"
#include "transmit_manager.h"
#include "uc_log.h"
#include <rtconfig.h>
#include <rtdevice.h>
#include <rthw.h>
#include <rtthread.h>
#include <stdio.h>

#define DBG_LVL DBG_LOG
#include <rtdbg.h>

typedef enum
{
    USE_BT_UNKNOWN = 0,
    USE_BT_HLK_B26,
    USE_BT_ESP32C2,
} use_bt_type_t;

#define SERIAL_NAME_LEN (8)
// 高电平保持4s复位
#define HLK_B26_BT_RST_PIN GET_PIN(D, 0)
// 设备使能引脚
#define HLK_B26_BT_EN_PIN GET_PIN(G, 7)

#define ESP32C2_BT_EN_PIN GET_PIN(A, 6)

#define RS485_EN_PIN GET_PIN(E, 14)
// 485收发指示引脚
#define RS485_RT_PIN GET_PIN(E, 15)

#define FAC_RS485_RX() rt_pin_write(RS485_RT_PIN, PIN_HIGH)
#define FAC_RS485_TX() rt_pin_write(RS485_RT_PIN, PIN_LOW)
#define FAC_COM_DEV_ENABLE(pin) rt_pin_write(pin, PIN_HIGH)
#define FAC_COM_DEV_DISABLE(pin) rt_pin_write(pin, PIN_LOW)

#define BT_MAC_DEFAULT "000000000000\r\n"
char g_bt_mac_addr[16] = {0};

static use_bt_type_t g_use_bt_type = USE_BT_UNKNOWN;

typedef struct serial_resource
{
    int module_id;
    char name[SERIAL_NAME_LEN];
    void *handle;
    struct serial_configure cfg;
} serial_resource_t;

static int factory_user_com_tx(serial_resource_t *res_p, unsigned char *data, unsigned int len)
{
    int ret_size = 0;
    // Check if the data is valid
    if ((RT_NULL == res_p) || (RT_NULL == res_p->handle) || (RT_NULL == data) || (len < 1))
    {
        TRACE_E("fac_user_com_tx input param error");
        return ret_size;
    }
    if (0 == res_p->module_id)
    {
        FAC_RS485_TX();
    }

    ret_size = rt_device_write(res_p->handle, 0, data, len);

    if (0 == res_p->module_id)
    {
        FAC_RS485_RX();
    }
    return ret_size;
}

static use_bt_type_t factory_bt_type_get(void)
{
    char *gw_hw_version = uc_static_get_gateway_base_cfg()->hardware_version;
    use_bt_type_t bt_type = USE_BT_UNKNOWN;

    if (rt_strcmp(gw_hw_version, CFG_HARDWARE_VERSION_V1_3) == 0)
    {
        bt_type = USE_BT_HLK_B26;
    }
    else if (rt_strcmp(gw_hw_version, CFG_HARDWARE_VERSION_V1_5) == 0)
    {
        bt_type = USE_BT_ESP32C2;
    }
    else if (rt_strcmp(gw_hw_version, CFG_HARDWARE_VERSION_V1_6) == 0)
    {
        bt_type = USE_BT_ESP32C2;
    }

    return bt_type;
}

static int factory_bt_at_send_cmd(serial_resource_t *res_p, char *at_cmd, char *at_cmd_ack, char *at_response)
{
    int ret = 0;
    int len = 0;
    int bt_read_len = 0;
    char bt_read_buf[256] = {0};
    rt_tick_t current_time;

    ret = factory_user_com_tx(res_p, at_cmd, rt_strlen(at_cmd));
    if (ret != rt_strlen(at_cmd))
    {
        return -RT_ERROR;
    }

    rt_memset(bt_read_buf, 0, sizeof(bt_read_buf));

    current_time = rt_tick_get();
    while (rt_tick_get() - current_time < 1000)
    {
        len = rt_device_read(res_p->handle, 0, &bt_read_buf[bt_read_len], 1);
        bt_read_len += len;
        rt_thread_mdelay(1);

        if (RT_NULL != rt_strstr(bt_read_buf, at_cmd_ack))
        {
            rt_thread_mdelay(100);
            len = rt_device_read(res_p->handle, 0, &bt_read_buf[bt_read_len], 256);
            bt_read_len += len;
            if (RT_NULL != at_response)
            {
                rt_memcpy(at_response, bt_read_buf, (bt_read_len - rt_strlen(at_cmd_ack) - 4));
            }
            return RT_EOK;
        }
    }

    return -RT_ERROR;
}

static int factory_bt_at_mode_entry(void)
{
    // 蓝牙模块进入AT模式
    if (g_use_bt_type == USE_BT_HLK_B26)
    {
        rt_pin_mode(HLK_B26_BT_RST_PIN, PIN_MODE_OUTPUT);
        rt_pin_write(HLK_B26_BT_RST_PIN, PIN_HIGH);
        rt_thread_mdelay(500);
        rt_pin_write(HLK_B26_BT_RST_PIN, PIN_LOW);
        rt_thread_mdelay(300);
    }
    else if (g_use_bt_type == USE_BT_ESP32C2)
    {
        rt_pin_mode(ESP32C2_BT_EN_PIN, PIN_MODE_OUTPUT);
        rt_pin_write(ESP32C2_BT_EN_PIN, PIN_LOW);
        rt_thread_mdelay(200);
        rt_pin_write(ESP32C2_BT_EN_PIN, PIN_HIGH);
        rt_thread_mdelay(500);
    }
    else
    {
        return -RT_ERROR;
    }

    return RT_EOK;
}

static int factory_bt_at_mode_exit(serial_resource_t *res_p)
{
    int ret = 0;
    char at_exit_cmd[32];

    rt_memset(at_exit_cmd, 0, sizeof(at_exit_cmd));

    if (g_use_bt_type == USE_BT_HLK_B26)
    {
        rt_sprintf(at_exit_cmd, "AT+REBOOT=1\r\n");
    }
    else if (g_use_bt_type == USE_BT_ESP32C2)
    {
        rt_sprintf(at_exit_cmd, "AT+BLESPP\r\n");
    }
    else
    {
        return -RT_ERROR;
    }

    ret = factory_bt_at_send_cmd(res_p, at_exit_cmd, "OK", RT_NULL);
    if (ret != RT_EOK)
    {
        TRACE_E("exit at mode error");
    }

    return ret;
}

static int hlk_b26_capture_ble_mac(serial_resource_t *res_p)
{
    int ret = RT_ERROR;
    int i = 0;
    rt_tick_t current_time = 0;
    char bt_mac_get_cmd[] = "AT+MAC=?\r\n";
    char bt_ver_get_cmd[] = "AT+VER=?\r\n";
    char bt_slave_mode_cmd[] = "AT+ROLE=1\r\n";
    char bt_at_response[256] = {0};
    char *str_point = RT_NULL;

    // 默认波特率115200.发送测试at指令，判断波特率是否为115200.如果指令成功，后面需要修改波特率。
    ret = factory_bt_at_send_cmd(res_p, bt_mac_get_cmd, "OK", bt_at_response);
    if (ret != RT_EOK)
    {
        return ret;
    }
    str_point = rt_strstr(bt_at_response, "AT+MAC=");
    if (str_point != RT_NULL)
    {
        str_point += 7;
        rt_memset(g_bt_mac_addr, 0, sizeof(g_bt_mac_addr));
        rt_memcpy(g_bt_mac_addr, str_point, 12);
        TRACE_D("ble_mac is %s", g_bt_mac_addr);
        g_bt_mac_addr[12] = '\r';
        g_bt_mac_addr[13] = '\n';
    }
    else
    {
        TRACE_E("ble_mac is null");
    }

    // 获取蓝牙固件版本号
    ret = factory_bt_at_send_cmd(res_p, bt_ver_get_cmd, "OK", bt_at_response);
    if (ret != RT_EOK)
    {
        return ret;
    }
    str_point = rt_strstr(bt_at_response, "AT+VER=");
    if (str_point != RT_NULL)
    {
        str_point += 7;
        TRACE_D("ble soft version is %s", str_point);
    }
    else
    {
        TRACE_E("ble soft version is null");
    }

    // 进入蓝牙从机模式
    return factory_bt_at_send_cmd(res_p, bt_slave_mode_cmd, "OK", RT_NULL);
}

static int esp32c2_capture_ble_mac(serial_resource_t *res_p)
{
    int ret = RT_ERROR;
    int i = 0;
    rt_tick_t current_time = 0;
    char bt_mac_get_cmd[] = "AT+BLEADDR?\r\n";
    char bt_broadcast_cmd[] = "AT+BLEADVDATAEX=";
    char bt_tx_power_cmd[] = "AT+RFPOWER=";
    char bt_at_send[256] = {0};
    char bt_at_response[256] = {0};
    char *str_point = RT_NULL;
    gw_base_cfg_t *gw_base_cfg = uc_static_get_gateway_base_cfg();

    // 清空缓冲区
    rt_device_read(res_p->handle, 0, bt_at_response, 256);

    // 默认波特率115200.发送测试at指令，判断波特率是否为115200.如果指令成功，后面需要修改波特率。
    ret = factory_bt_at_send_cmd(res_p, bt_mac_get_cmd, "OK", bt_at_response);
    if (ret != RT_EOK)
    {
        return ret;
    }
    str_point = rt_strstr(bt_at_response, "+BLEADDR:");
    if (str_point != RT_NULL)
    {
        str_point += 9;
        char *bt_mac = rt_calloc(1, 16);
        sscanf(str_point, "\"%02s:%02s:%02s:%02s:%02s:%02s\"", &bt_mac[0], &bt_mac[2], &bt_mac[4], &bt_mac[6], &bt_mac[8], &bt_mac[10]);

        rt_memset(g_bt_mac_addr, 0, sizeof(g_bt_mac_addr));
        rt_memcpy(g_bt_mac_addr, bt_mac, 12);
        TRACE_D("ble_mac is %s", g_bt_mac_addr);
        g_bt_mac_addr[12] = '\r';
        g_bt_mac_addr[13] = '\n';

        rt_free(bt_mac);
    }
    else
    {
        TRACE_E("ble_mac is null");
    }

    // 设置广播参数
    rt_memset(bt_at_send, 0, sizeof(bt_at_send));
    char *bt_broadcast_name = rt_calloc(sizeof(char), 16);
    rt_sprintf(bt_broadcast_name, "GW-%u", gw_base_cfg->dev_id);
    rt_sprintf(bt_at_send, "%s\"%s\",\"%s\",\"%s\",%d\r\n", bt_broadcast_cmd, bt_broadcast_name, "NULL", "NLL", 1);
    ret = factory_bt_at_send_cmd(res_p, bt_at_send, "OK", RT_NULL);
    rt_free(bt_broadcast_name);

    if (ret != RT_EOK)
    {
        TRACE_E("set ble broadcast error");
        return ret;
    }

    // 设置发射功率
    rt_memset(bt_at_send, 0, sizeof(bt_at_send));
    rt_sprintf(bt_at_send, "%s%d\r\n", bt_tx_power_cmd, 15);
    ret = factory_bt_at_send_cmd(res_p, bt_at_send, "OK", RT_NULL);

    if (ret != RT_EOK)
    {
        TRACE_E("set ble tx power error");
        return ret;
    }

    return RT_EOK;
}

static int factory_bt_init(serial_resource_t *res_p)
{
    if (g_use_bt_type == USE_BT_HLK_B26)
    {
        rt_pin_mode(HLK_B26_BT_EN_PIN, PIN_MODE_OUTPUT);
        FAC_COM_DEV_ENABLE(HLK_B26_BT_EN_PIN);

        factory_bt_at_mode_entry();
        if (RT_EOK != hlk_b26_capture_ble_mac(res_p))
        {
            return -RT_ERROR;
        }
    }
    else if (g_use_bt_type == USE_BT_ESP32C2)
    {
        factory_bt_at_mode_entry();

        if (RT_EOK != esp32c2_capture_ble_mac(res_p))
        {
            return -RT_ERROR;
        }
    }
    else
    {
        TRACE_E("unknown hw version, bt init failed");
        return -RT_ERROR;
    }

    return factory_bt_at_mode_exit(res_p);
}

static int factory_com_init(serial_resource_t *res_p, factory_test_type_e test_type, char *name)
{
    int ret = RT_ERROR;
    if (RT_NULL == res_p)
        return ret;
    res_p->handle = rt_device_find(res_p->name);
    TRACE_D("user_com_init %s", res_p->name);

    if (res_p->handle == RT_NULL)
    {
        TRACE_E("%s handle == NULL", res_p->name);
        factory_test_result(test_type, name, FACTORY_TEST_FAIL, "uart handle fail");
        return -RT_ERROR;
    }

    /* using DMA mode first */
    ret = rt_device_open(res_p->handle, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_RX);
    /* using interrupt mode when DMA mode not supported */
    if (ret == -RT_EIO)
    {
        ret = rt_device_open(res_p->handle, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
    }

    // RT_DEVICE_FLAG_DMA_RX
    // ret = rt_device_open(res_p->handle, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
    if (ret)
    {
        TRACE_E("%s open failed", res_p->name);
        factory_test_result(test_type, name, FACTORY_TEST_FAIL, "uart open fail");
        return ret;
    }

    if (res_p->module_id == 1)
    {
        g_use_bt_type = factory_bt_type_get();
        switch (g_use_bt_type)
        {
        case USE_BT_HLK_B26:
            res_p->cfg.baud_rate = BAUD_RATE_115200;
            break;
        case USE_BT_ESP32C2:
            res_p->cfg.baud_rate = BAUD_RATE_460800;
            break;
        default:
            break;
        }
    }

    ret = rt_device_control(res_p->handle, RT_DEVICE_CTRL_CONFIG, &res_p->cfg);
    if (ret != RT_EOK)
    {
        TRACE_E("%s control failed", res_p->name);
        factory_test_result(test_type, name, FACTORY_TEST_FAIL, "uart control fail");
        return ret;
    }

    switch (res_p->module_id)
    {
    case 0: // 485
        rt_pin_mode(RS485_EN_PIN, PIN_MODE_OUTPUT);
        FAC_COM_DEV_ENABLE(RS485_EN_PIN);
        rt_pin_mode(RS485_RT_PIN, PIN_MODE_OUTPUT);
        FAC_RS485_RX();
        break;
    case 1: // bt
        if (rt_strncmp(g_bt_mac_addr, BT_MAC_DEFAULT, 14) == 0)
        {
            ret = factory_bt_init(res_p);
            if (RT_EOK != ret)
            {
                factory_test_result(test_type, name, FACTORY_TEST_FAIL, "bt init fail");
            }
        }
        break;
    default:
        break;
    }

    rt_thread_mdelay(500);

    return ret;
}

int factory_uart_test(serial_resource_t *s_serial_res, factory_test_type_e test_type, char *name)
{
    unsigned int send_time = 0;
    unsigned int current_time = 0;
    char factory_data = 0;
    char factory_buf[FACTORY_UART_LEN * 2] = {0};
    int factory_buf_len = 0;
    int len = 0;
    int res = 1;

    if (RT_EOK != factory_com_init(s_serial_res, test_type, name))
    {
        return -RT_ERROR;
    }

    current_time = rt_tick_get();
    while (rt_tick_get() - current_time < 20000)
    {
        if ((rt_tick_get() - send_time) >= 1000)
        {
            // 工厂测试，发送固定数据，请收到固定数据后将相同的数据发送过来
            factory_user_com_tx(s_serial_res, g_bt_mac_addr, rt_strlen(g_bt_mac_addr));
            factory_buf_len = 0;
            rt_memset(factory_buf, 0, sizeof(factory_buf));
            send_time = rt_tick_get();
        }

        len = rt_device_read(s_serial_res->handle,
                             -1,
                             &factory_buf[factory_buf_len],
                             FACTORY_UART_LEN);
        if (len > 0)
        {
            factory_buf_len += len;
            if (factory_buf_len >= rt_strlen(g_bt_mac_addr))
            {
                if (RT_NULL != rt_strstr(factory_buf, "\r\n") || factory_buf_len >= FACTORY_UART_LEN)
                {
                    if (rt_strncmp(factory_buf, g_bt_mac_addr, rt_strlen(g_bt_mac_addr)) == 0)
                    {
                        res = 0;
                        break;
                    }
                    factory_buf_len = 0;
                    rt_memset(factory_buf, 0, sizeof(factory_buf));
                }
            }
        }
        else
        {
            rt_thread_mdelay(20);
        }
    }

    if (res == 0)
    {
        factory_test_result(test_type, name, FACTORY_TEST_SUCCESS, "NULL");
        TRACE_D("%s uart read write data equal, success", name);
    }
    else
    {
        char remake[32] = {0};
        rt_snprintf(remake, 32, "%s communication fail", factory_get_key(test_type));
        factory_test_result(test_type, name, FACTORY_TEST_FAIL, remake);
        TRACE_D("%s uart read write data unequal, fail", name);
    }

    TRACE_D("%s factory_buf is %s", name, factory_buf);

    return res;
}

int fac_485_uart_test(void)
{
    serial_resource_t rs_serial_res = {0, USER_COM_485_NAME, NULL, FAC_RS485_CONFIG};
    int ret = factory_uart_test(&rs_serial_res, UART485_TEST, factory_get_key(UART485_TEST));
    if (ret == 1)
    {
        TRACE_D("485 uart test fail");
    }
    else
    {
        TRACE_D("485 uart test success");
    }
    return ret;
}
#ifdef FINSH_USING_MSH
MSH_CMD_EXPORT_ALIAS(fac_485_uart_test, rs485_test, test rs485 uart send receive);
#endif
int fac_ble_uart_test(void)
{
    serial_resource_t ble_serial_res = {1, USER_COM_BT_NAME, NULL, FAC_BT_CONFIG};
    int ret = factory_uart_test(&ble_serial_res, BLUETOOTH_TEST, factory_get_key(BLUETOOTH_TEST));
    if (ret == 1)
    {
        TRACE_D("ble uart test fail");
    }
    else
    {
        TRACE_D("ble uart test success");
    }
    return ret;
}

#ifdef FINSH_USING_MSH
MSH_CMD_EXPORT_ALIAS(fac_ble_uart_test, ble_test, test ble uart send receive);
#endif

int fac_bt_mac_addr_get(void)
{
    serial_resource_t ble_serial_res = {1, USER_COM_BT_NAME, NULL, FAC_BT_CONFIG};
    serial_resource_t *res_p = &ble_serial_res;

    rt_memset(g_bt_mac_addr, 0, sizeof(g_bt_mac_addr));
    rt_sprintf(g_bt_mac_addr, BT_MAC_DEFAULT);

    int result = factory_com_init(res_p, BLUETOOTH_TEST, factory_get_key(BLUETOOTH_TEST));

    rt_thread_mdelay(500);

    return result;
}
#ifdef FINSH_USING_MSH
MSH_CMD_EXPORT_ALIAS(fac_bt_mac_addr_get, ble_mac_get, ble mac get);
#endif
